/* ----------------------------------------------------------------------
 *	Shadow Quest
 *	Copyright (C) 2009 Prageeth Silva <prageeth@thenewcoders.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *  ----------------------------------------------------------------------
 */
package map;

import org.newdawn.slick.SlickException;

/** Items that can be picked, dropped and used by units
 * 
 */
public abstract class MapEntity implements java.io.Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private World world;
    private String name;					// name of the item
    private double speed;					// position of the item on the map
    private boolean onMap;					// status of the item, if its picked up or not
    private int width, height, frameWidth, frameHeight;
    private double x, y;

    /** Create a new Item object .
     * @param type The type of item.
     * @param x The x coordinate of the item (in pixels).
     * @param y The y coordinate of the item (in pixels).
     * @param value The value of the item.
     */
    public MapEntity(World world)
        throws SlickException
    {
        this.setWorld(world);
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public double getSpeed()
    {
        return speed;
    }

    public void setSpeed(double speed)
    {
        this.speed = speed;
    }

    public boolean isOnMap()
    {
        return onMap;
    }

    public void setOnMap(boolean onMap)
    {
        this.onMap = onMap;
    }

    public void setX(double x)
    {
        this.x = x;
    }

    public double getX()
    {
        return this.x;
    }

    public void setY(double y)
    {
        this.y = y;
    }

    public double getY()
    {
        return this.y;
    }

    public double getWidth()
    {
        return this.width;
    }

    public void setWidth(int width)
    {
        this.width = width;
    }

    public double getHeight()
    {
        return this.height;
    }

    public void setHeight(int height)
    {
        this.height = height;
    }

    public void setSize(int width, int height)
    {
        this.setWidth(width);
        this.setHeight(height);
    }

    public double getMinX(double x) {
        return x - this.getWidth()/2;
    }

    public double getMaxX(double x) {
        return x + this.getWidth()/2;
    }

    public double getMinY(double y) {
        return y - this.getHeight()/2;
    }

    public double getMaxY(double y) {
        return y + this.getHeight()/2;
    }

    public double getMinX() {
        return this.getX() - this.getWidth()/2;
    }

    public double getMaxX() {
        return this.getX() + this.getWidth()/2;
    }

    public double getMinY() {
        return this.getY() - this.getHeight()/2;
    }

    public double getMaxY() {
        return this.getY() + this.getHeight()/2;
    }

    public boolean collides(MapEntity m) {
        boolean cx = (m.getMinX() >= this.getMinX() && m.getMinX() <= this.getMaxX());
        cx |= (m.getMaxX() >= this.getMinX() && m.getMaxX() <= this.getMaxX());
        boolean cy = (m.getMinY() >= this.getMinY() && m.getMinY() <= this.getMaxY());
        cy |= (m.getMaxY() >= this.getMinY() && m.getMaxY() <= this.getMaxY());
        return (cx && cy);
    }

    /** Checks if a given point on the map is occupied by this unit.
     * @param x The x coordinate.
     * @param y The y coordinate.
     */
    public boolean isOccupied(double x, double y) {
        return (x >= this.getMinX() && x <= this.getMaxX() && y >= this.getMinY() && y <= getMaxY());
    }

    /** Get the Height of the unit.
     * @return The height.
     */
    protected int getFrameHeight()
    {
        return this.frameHeight;
    }

    protected void setFrameHeight(int frameHeight)
    {
        this.frameHeight = frameHeight;
    }

    /** Get the Width of the unit.
     * @return The width.
     */
    protected int getFrameWidth()
    {
        return this.frameWidth;

    }

    protected void setFrameWidth(int frameWidth)
    {
        this.frameWidth = frameWidth;
    }

    /** Move the unit to a point, but does NOT check for collision detection.
     * @param x The X coordinate (pixels).
     * @param y The Y coordinate (pixels).
     */
    public void moveToTile(int x, int y, boolean center) {
        // TODO get world in this method to get the tile sizes
        double halfTile = (center ? 0.5f : 0f);
        double tx = (x + halfTile) * this.getWorld().getMap().getTileWidth();
        double ty = (y + halfTile) * this.getWorld().getMap().getTileHeight();
        this.moveTo(tx, ty);
    }

    /** Move the unit to a point, but does NOT check for collision detection.
     * @param x The X coordinate (pixels).
     * @param y The Y coordinate (pixels).
     */
    public void moveToTile(int x, int y) {
        this.moveToTile(x, y, true);
    }

    /** Move the unit to a point, but does NOT check for collision detection.
     * @param x The X coordinate (pixels).
     * @param y The Y coordinate (pixels).
     */
    public void moveTo(double x, double y) {
        this.setX(x);
        this.setY(y);
    }

    public final void setWorld(World world) {
        this.world = world;
    }

    protected World getWorld() {
        return this.world;
    }
    
}
